package educar.models;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;

import educar.db.DbConnection;
import educar.db.JPA;

/**
 * 
 * @author Baldani-Ocejo-Padula
 * 
 * Clase que modela un "usuario del sistema". Por esto se entiende a alguien
 * que tiene contacto directo y manipula la aplicacion; posee un rol que determina
 * las acciones que puede realizar y posee nombre-password para
 * poder identificarse al usar la aplicacion.
 * 
 */
public class User
{
    private static JPA jpa = new JPA();
    private String username;
    private String password;
    private String role;
    private String dniUser;

    /**
     * 
     * @param dniUser : el dni de la persona que se corresponde a este usuario del sistema
     * @param username : nombre con el que el usuario se identificara en el sistema
     * @param password : passoword que el usuario usara para identificarse en el sistema
     * @param role : rol que le corresponde al usuario, puede ser administrador, alumno o docente.
     */
    public User(String dniUser, String username, String password, String role)
    {
        this.setDniUser(dniUser);
        this.setUsername(username);
        this.setPassword(password);
        this.setRole(role);
    }

    /**
     * 
     * @param username : nombre del usuario que se quiere autenticar en el sistema
     * @param password : password corresponiente al usuario que se quiere autenticar en el sistema
     * @return verdadero si el usuario se autentico correctamente, falso si 
     * el password fue incorrecto o direcamente el usuario no exite en el sistema
     */
    public static boolean authenticate(String username, String password)
    {
        try
        {
            User u = getUserByUsername(username);

            if (password.equals(u.getPassword()))
            {
                Session.setCurrentUser(u);
                return true;
            }
        }
        catch (userNotFound ex)
        {
            return false;
        }

        return false;
    }

    /**
     * metodo que hace persistente en la base de datos el Usuario representado por 
     * este objeto
     * 
     * @return verdadero si el usuario pudo guardarse en el sistema, 
     * falso si el usuario ya existia o hubo otro error por el cual no se genero
     * la persistencia.
     */
    public boolean save()
    {
        try
        {
            User.getUserByUsername(username);
            return false;
        }
        catch (userNotFound e1)
        {
            String[] columns = { "dniUser", "username", "password", "role" };

            PreparedStatement stm = jpa.newRecord(DbConnection.bd+".users", columns);

            try
            {
                stm.setString(1, dniUser);
                stm.setString(2, username);
                stm.setString(3, password);
                stm.setString(4, role);
            }
            catch (SQLException e)
            {
                e.printStackTrace();
                return false;
            }

            jpa.create(stm);
            return true;
        }
    }

    /**
     * Metodo que destruye la persistencia en la base de datos del usuario representado
     * por esta instancia en la aplicacion.
     */
    public void destroy()
    {
        jpa.destroy("users", "username", this.getUsername());
    }

    /**
     * 
     * @param username : nombre del usuario al que se quiere acceder en la base de datos
     * @return Una instancia de clase User que representa a un usuario de la aplicacion en
     * la base de datos y tiene nombre igual al pasado por parametro
     * @throws userNotFound : si dicho usuario no existe en la base de datos
     */
    public static User getUserByUsername(String username) throws userNotFound
    {
        ResultSet rs = null;
        User u = null;

        rs = jpa.getByField("users", "username", username);

        try
        {
            if (rs.next())
            {
                u = new User(rs.getString(1), rs.getString(2), rs.getString(3), rs.getString(4));
            }
            else
            {
                throw new userNotFound();
            }
        }
        catch (SQLException e)
        {
            e.printStackTrace();
        }

        return u;
    }

    /**
     * 
     * @param dniUser : dni del usuario al que se quiere acceder en la base de datos
     * @param role : rol del usuario al que se queire acceder en la base de datos
     * @return Una instancia de clase User que representa a un usuario de la aplicacion en
     * la base de datos y tiene dni y rol iguales a los pasados por parametro
     * @throws userNotFound : si dicho usuario no existe en la base de datos
     *
     */
    public static User getUserByDniUserRole(String dniUser, String role) throws userNotFound
    {
        ResultSet rs = null;
        User u = null;

        rs = jpa.getByField("users", "dniUser", dniUser);

        try
        {
            while (rs.next())
            {
                if (rs.getString(4).compareTo(role) == 0)
                    u = new User(rs.getString(1), rs.getString(2), rs.getString(3), rs.getString(4));
            }
        }
        catch (SQLException e)
        {
            e.printStackTrace();
        }
        if (u == null)
            throw new userNotFound();
        return u;
    }

    /**
     * Metodo que actualiza la base de datos con los datos actuales que tiene esta
     * instancia de la clase Usuario en la aplicacion.
     */
    public void update()
    {
        HashMap<String, String> m = new HashMap<String, String>();
        m.put("password", password);
        m.put("dniUser", dniUser);
        jpa.genericUpdate("users", m, "username", username);

    }

    /**
     * 
     * @return el nombre del usuario
     */
    public String getUsername()
    {
        return username;
    }

    /**
     * settea el nombre de este usuario con el pasado por parametro
     * 
     * @param username : nombre del usuario que se quiere settear como nombre actual
     */
    public void setUsername(String username)
    {
        this.username = username;
    }

    /**
     * 
     * @return el password del usuario
     */
    public String getPassword()
    {
        return password;
    }

    /**
     * settea el password de este usuario con el pasado por parametro
     * 
     * @param password : nombre del usuario que se quiere settear como password actual
     */
    public void setPassword(String password)
    {
        this.password = password;
    }


    /**
     * 
     * @return el rol del usuario
     */
    public String getRole()
    {
        return role;
    }

    /**
     * settea el rol de este usuario con el pasado por parametro
     * 
     * @param password : rol del usuario que se quiere settear como rol actual
     */
    public void setRole(String role)
    {
        this.role = role;
    }

    /**
     * settea el dni de este usuario con el pasado por parametro
     * 
     * @param password : dni del usuario que se quiere settear como dni actual
     */
    public void setDniUser(String dniUser)
    {
        this.dniUser = dniUser;
    }

    /**
     * 
     * @return el dni del usuario
     */
    public String getDniUser()
    {
        return dniUser;
    }

}
